package main

/*
	处理请求
*/
import (
	"fmt"
	"net"
	"shell/common"
	"shell/common/packages"
	"shell/global"
	"shell/utils"
)

// 处理Shell命令请求
func handleShellCmd(stream *common.QuicStream, pkg *packages.ShellCmdReq) {
	respPkg := new(packages.ShellCmdResp)
	respPkg.CmdUUID = pkg.CmdUUID
	respPkg.TargetUUID = globalCfg.UUID
	respPkg.SetRole(Role)
	if pkg.TargetUUID != globalCfg.UUID {
		// uuid不匹配
		if globalCfg.Relay != nil && globalCfg.Relay.Enable == true {
			// 本节点是中继
			/* todo */
			return
		} else {
			// 本节点不是中继，
			respPkg.CmdOutput = []byte("target uuid error not match !!!")
			respPkg.CmdExitCode = -1
			err := stream.WritePackage(respPkg)
			if err != nil {
				common.HandleErr(err)
				return
			}
			stream.CloseStreamSync(Role, true)
			return
		}
	}
	out, code, err := utils.RunCmd(string(pkg.ShellCmd))
	respPkg.CmdExitCode = code
	if err != nil {
		respPkg.CmdOutput = []byte(err.Error())
	} else {
		respPkg.CmdOutput = out
	}
	err = stream.WritePackage(respPkg)
	if err != nil {
		common.HandleErr(err)
		return
	}
	stream.CloseStreamSync(Role, true)
}

// 处理端口转发请求
func handlePortRedir(stream *common.QuicStream, pkg *packages.PortRedirReq) {
	pkgResp := pkg.ToResp(Role)
	if pkg.TargetUUID != globalCfg.UUID {
		// uuid不匹配
		if globalCfg.Relay != nil && globalCfg.Relay.Enable == true {
			// 本节点是中继
			/* todo */
			return
		} else {
			// 本节点不是中继
			pkgResp.IsOk = false
			pkgResp.ErrorInfo = []byte("target uuid error not match !!!")
			err := stream.WritePackage(pkgResp)
			if err != nil {
				common.HandleErr(err)
				return
			}
			stream.CloseStreamSync(Role, true)
			return
		}
	}
	addr := net.JoinHostPort(pkg.RedirDestIP.String(), fmt.Sprintf("%d", pkg.RedirDestPort))
	// 是开启端口转发
	if pkg.Start {
		tcpConn, err := net.Dial("tcp", addr)
		if err != nil {
			logger.Errorf(0, "error open tcp conn: %v", err)
			pkgResp.IsOk = false
			pkgResp.ErrorInfo = []byte(err.Error())
			err := stream.WritePackage(pkgResp)
			if err != nil {
				common.HandleErr(err)
				return
			}
			stream.CloseStreamSync(Role, true)
		}
		pkgResp.IsOk = true
		err = stream.WritePackage(pkgResp)
		if err != nil {
			common.HandleErr(err)
			return
		}
		common.NewTimeoutRWCPairWarp(stream, tcpConn, global.DefaultIdleTime, timeoutWatcher).RedirSyncNoKey()
	} else {
		pkgResp.IsOk = false
		pkgResp.ErrorInfo = []byte("controlled end only accept port redir start action")
		err := stream.WritePackage(pkgResp)
		if err != nil {
			common.HandleErr(err)
			return
		}
		stream.CloseStreamSync(Role, true)
	}
}

// 处理socks5转发请求
func handleSocks5(stream *common.QuicStream, pkg *packages.Socks5RedirReq) {
	pkgResp := pkg.ToResp(Role)
	if pkg.TargetUUID != globalCfg.UUID {
		// uuid不匹配
		if globalCfg.Relay != nil && globalCfg.Relay.Enable == true {
			// 本节点是中继
			/* todo */
			logger.Errorf(0, "error socks5 redir request: %s:%d", pkg.TargetAddr, pkg.TargetPort)
			return
		} else {
			// 本节点不是中继
			logger.Errorf(0, "error socks5 redir request: %s:%d", pkg.TargetAddr, pkg.TargetPort)
			pkgResp.IsOk = false
			pkgResp.ErrorInfo = []byte("target uuid error not match !!!")
			err := stream.WritePackage(pkgResp)
			if err != nil {
				common.HandleErr(err)
			}
			stream.CloseStreamSync(Role, true)
			return
		}
	}
	addr := ""
	if pkg.TargetAType == packages.ATypeIPv4 {
		ip := net.IPv4(pkg.TargetAddr[0], pkg.TargetAddr[1], pkg.TargetAddr[2], pkg.TargetAddr[3]).String()
		addr = net.JoinHostPort(ip, fmt.Sprintf("%d", pkg.TargetPort))
	} else if pkg.TargetAType == packages.ATypeDomain {
		addr = net.JoinHostPort(string(pkg.TargetAddr), fmt.Sprintf("%d", pkg.TargetPort))
	}
	tcpConn, err := net.Dial("tcp", addr)
	if err != nil {
		logger.Errorf(0, "error open tcp conn: %v", err)
		pkgResp.IsOk = false
		pkgResp.ErrorInfo = []byte(err.Error())
		err := stream.WritePackage(pkgResp)
		if err != nil {
			common.HandleErr(err)
			return
		}
		stream.CloseStreamSync(Role, true)
		return
	}
	pkgResp.IsOk = true
	err = stream.WritePackage(pkgResp)
	if err != nil {
		common.HandleErr(err)
		tcpConn.Close()
		return
	}
	common.NewTimeoutRWCPairWarp(stream, tcpConn, global.DefaultIdleTime, timeoutWatcher).RedirSyncNoKey()
}
